#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <memory.h>
#include <malloc.h>
#include <errno.h>
#include <netinet/in.h>
#include <time.h>
#include "rfs-defs.h"
int numread;

int recibir(PACKAGE *package, struct sockaddr_in *sock, int flag);
int enviar(PACKAGE *package, struct sockaddr_in sock, int mode);
long segmentar(char * data, PACKAGE * package, struct sockaddr_in sock, unsigned long size);
long ensamblar(char ** data, PACKAGE * package, struct sockaddr_in sock);

long
rls(PACKAGE *package) {
    // envío el comando
    package->op = RLS;
    enviar(package, dir, 0);

    // creo el puntero que va a contener el resultado final
    char * output = (char *) malloc(1);
    output[0] = '\0';

    long n = ensamblar(&output, package, dir);

    // imprimo resultado
    printf("Resultado\n");
    printf("-----------------\n");
    printf("%s\n", output);
    printf("-----------------\n");

    // retorno la cantidad de bytes leídos
    return n;
}

long
rcd(PACKAGE *package) {

    // envío el comando
    package->op = RCD;
    enviar(package, dir, 0);

    // creo el puntero que va a contener el resultado final
    char * output = (char *) malloc(1);
    output[0] = '\0';

    long n = ensamblar(&output, package, dir);

    // imprimo resultado
    printf("Resultado\n");
    printf("-----------------\n");
    printf("%s", output);
    printf("-----------------\n");

    // retorno cantidad de bytes leídos
    return n;
}

long
get(PACKAGE *package) {

    FILE * file = NULL;

    long n;

    // creo el puntero que va a contener el resultado final
    char * output = (char *) malloc(sizeof (char));
    output[0] = '\0';

    char * result = (char *) malloc(sizeof (char));
    result[0] = '\0';

    char * file_name = (char *) malloc(DATA_LENGTH);
    strncpy(file_name, package->data, DATA_LENGTH);
    package->op = GET;
    enviar(package, dir, 0);

    if (recibir(package, NULL, MSG_DONTWAIT) < 0) {
        output = (char *) realloc(output, 101 + strlen(file_name));
        sprintf(output, "Ocurrió un error al solicitar al servidor el archivo '%s'.\n"
                "El servidor no respondió a la solicitud.\n", file_name);
    } else
        if (package->op == OK) {
        package->op = ACK;
        enviar(package, dir, 0);
        file = fopen(file_name, "w");
        n = ensamblar(&result, package, dir);
        fwrite(result, sizeof (char), n, file);
        fclose(file);
    } else
        if (package->op == ERROR) {
        package->op = ACK;
        enviar(package, dir, 0);
        output = (char *) realloc(output, 127 + strlen(file_name));
        sprintf(output, "Ocurrió un error al solicitar al servidor el archivo '%s'.\n"
                "El archivo no existe o el servidor no tiene permiso para leerlo.\n", file_name);
    }
    printf("-----------------\n");
    if (strlen(output) == 0) {
        output = (char *) realloc(output, 87 + strlen(file_name) + sizeof (int) + 1);
        sprintf(output, "Resultado:\nSe descargó correctamente el archivo '%s'.\n"
                "Se transmitieron %lu bytes en total.\n",
                file_name, n);
    }
    printf("%s", output);
    printf("-----------------\n");

    free(file_name);
    return n;
}

long
put(PACKAGE *package) {
    long n;
    int i;

    char * file_name = (char *) malloc(DATA_LENGTH);
    strncpy(file_name, package->data, DATA_LENGTH);

    FILE * file;
    if ((file = fopen(file_name, "r")) == NULL) {
        perror("Ocurrió un error al intentar abrir el archivo que solicitó subir al servidor.\n");
        return ERROR;
    }

    // creo el puntero que va a contener el resultado final
    char * output = (char *) malloc(1);
    output[0] = '\0';

    char * result = (char *) malloc(sizeof (char));
    result[0] = '\0';

    char buffer[DATA_LENGTH];


    package->op = PUT;

    //envío comando y nombre de archivo
    enviar(package, dir, 0);
    // recibo confirmación
    if (recibir(package, NULL, MSG_DONTWAIT) < 0) {
        output = (char *) realloc(output, 100 + strlen(file_name) + 1);
        sprintf(output, "Ocurrió un error al solicitar al servidor subir el archivo %s.\n"
                "No se ha recibido el OK del servidor.\n", file_name);
    } else
        // si no hubo error al crear el archivo en el servidor
        if (package->op == OK) {
        package->op = ACK;
        enviar(package, dir, 0);

        i = 0;
        do {
            fseek(file, i*DATA_LENGTH, SEEK_SET);
            n = fread(buffer, sizeof (char), DATA_LENGTH, file);
            result = realloc(result, i * DATA_LENGTH + n);
            memmove(&result[i * DATA_LENGTH], buffer, n);
            i++;
        } while (n == DATA_LENGTH);
        fclose(file);
        n = segmentar(result, package, dir, (i - 1) * DATA_LENGTH + n);
    } else {
        output = (char *) realloc(output, 101 + strlen(file_name) + 1);
        sprintf(output, "Ocurrió un error al solicitar al servidor subir el archivo %s.\n"
                "El servidor no pudo crear el archivo.\n", file_name);
    }
    // hasta que haya leído y enviado una porción menor al tamaño máximo (señal del fin de archivo)
    printf("-----------------\n");
    if (strlen(output) == 0) {
        output = (char *) realloc(output, 84 + strlen(file_name) + 11);
        sprintf(output, "Resultado:\nSe subió correctamente el archivo '%s'.\n"
                "Se transmitieron %lu bytes en total.\n",
                file_name, n);
    }
    printf("%s", output);
    printf("-----------------\n");

    free(file_name);
    return n;
}

